﻿using Dapper;
using Gear.Core;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using SqlSugar;

namespace Gear.Web.Api.DynamicCoding
{
    public interface ICompiler
    {
        Assembly Compile(string text, params Assembly[] referencedAssemblies);
    }

    public class Compiler : ICompiler
    {
        public Assembly Compile(string text, params Assembly[] referencedAssemblies)
        {

            // 添加要引用的程序集
            List<MetadataReference> refs = new List<MetadataReference>() {
                
                MetadataReference.CreateFromFile (typeof (object).Assembly.Location),
                MetadataReference.CreateFromFile (typeof (List<int>).Assembly.Location),
                MetadataReference.CreateFromFile (typeof (ASCIIEncoding).Assembly.Location),
                MetadataReference.CreateFromFile (typeof (IDapperRepository).Assembly.Location),
                MetadataReference.CreateFromFile (typeof (ISqlSugarRepository).Assembly.Location),
                MetadataReference.CreateFromFile (typeof (IDbTransaction).Assembly.Location),
                MetadataReference.CreateFromFile (typeof (Enumerable).Assembly.Location),
                MetadataReference.CreateFromFile (typeof (HttpPostAttribute).Assembly.Location)
            };

            // 语法树编译
            var references = referencedAssemblies.Select(it => MetadataReference.CreateFromFile(it.Location));
            var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary);
            var assemblyName = "_" + Guid.NewGuid().ToString("D");
            var syntaxTrees = new SyntaxTree[] { CSharpSyntaxTree.ParseText(text) };
            var compilation = CSharpCompilation.Create(assemblyName, syntaxTrees, references, options)
                .WithOptions(new CSharpCompilationOptions(
                    OutputKind.DynamicallyLinkedLibrary,
                    usings: null,
                    optimizationLevel: OptimizationLevel.Debug, // TODO
                    checkOverflow: false, // TODO
                    allowUnsafe: true, // TODO
                    platform: Platform.AnyCpu,
                    warningLevel: 4,
                    xmlReferenceResolver: null
                ))
                .AddReferences(refs);
            using var stream = new MemoryStream();
            var compilationResult = compilation.Emit(stream);
            if (compilationResult.Success)
            {
                stream.Seek(0, SeekOrigin.Begin);
                return Assembly.Load(stream.ToArray());
            }
            else
            {
                //记录编译错误日志
            }
            throw new InvalidOperationException("Compilation error");
        }
    }
}
